using System;
using System.Collections;
using System.Xml;
using DesignByContract;
using Outcoding.GraphGenerator.Entities;
using Outcoding.GraphGenerator.Util.Logging;

namespace Outcoding.GraphGenerator.Composition{
    public class SlideBuilder : BuilderBase{
        #region Attributes

        private string indexAttr = "index";
        private string layoutAttr = "layout";

        #endregion

        private readonly string mNodeName = XmlTagNames.slide.ToString();

        private XmlNodeList mNodeList;

        private string mNodePath{
            get { return "/presentation/slidecollection/" + mNodeName; }
        }

        public override void SelectNode(XmlDocument document){
            Check.Require(document != null, "XmlDocument cannot be null.");

            mNodeList = document.SelectNodes(mNodePath);

            Check.Ensure(mNodeList != null, "Slide node could not be created.");
        }

        public override void Compose(){
            try{
                BuildObject(mNodeList);
            }
            catch (PreconditionException preExc){
                LogManager.Instance.LogWarning("Slide entity could not be created; process aborted.", preExc);
            }
        }

        public override void Compose(XmlNode node){
            throw new Exception("The method or operation is not implemented.");
        }

        public override void AppendToParent(object parent){
            var slideCollection = (SlideCollection) parent;
            var slideList = (ArrayList) mProduct;
            foreach (Slide tmpSlide in slideList)
                slideCollection.Add(tmpSlide);
        }

        private void BuildObject(XmlNodeList slideXmlNodeList){
            var slideList = new ArrayList();

            foreach (XmlNode tmpNode in slideXmlNodeList){
                var slide = new Slide();
                try{
                    slide.Layout = ParseLayoutAttribute(tmpNode);
                    if (tmpNode.Attributes[indexAttr] != null)
                        slide.Index = ParseIndexAttribute(tmpNode);
                    else
                        slide.Index = Int32.MinValue; //used to distinguish a valid index
                }
                catch (PreconditionException preExc){
                    //log error
                    slide = null;
                    throw;
                }
                slideList.Add(slide);
            }
            mProduct = slideList;
        }

        private SlideLayout ParseLayoutAttribute(XmlNode slideXmlNode){
            Check.Require(slideXmlNode.Attributes[layoutAttr] != null, "layout attribute not present");
            return ConvertLayoutFromName(slideXmlNode.Attributes[layoutAttr].Value);
        }

        private SlideLayout ConvertLayoutFromName(string layoutName){
            Check.Require(layoutName != null, "Layout name not defined");

            SlideLayout layoutValue = SlideLayout.ppLayoutUnknown;
            switch (layoutName){
                case "ppLayoutBlank":
                    layoutValue = SlideLayout.ppLayoutBlank;
                    break;
                case "ppLayoutTitleOnly":
                    layoutValue = SlideLayout.ppLayoutTitleOnly;
                    break;
                case "ppLayoutTitle":
                    layoutValue = SlideLayout.ppLayoutTitle;
                    break;
                case "ppLayoutLargeObject":
                    layoutValue = SlideLayout.ppLayoutLargeObject;
                    break;
                case "ppLayoutText":
                    layoutValue = SlideLayout.ppLayoutText;
                    break;
                case "ppLayoutTwoColumnText":
                    layoutValue = SlideLayout.ppLayoutTwoColumnText;
                    break;
                case "ppLayoutObjectOverText":
                    layoutValue = SlideLayout.ppLayoutObjectOverText;
                    break;
                case "ppLayoutTextAndTwoObjects":
                    layoutValue = SlideLayout.ppLayoutTextAndTwoObjects;
                    break;
                case "ppLayoutTwoObjectsAndText":
                    layoutValue = SlideLayout.ppLayoutTwoObjectsAndText;
                    break;
                case "ppLayoutTwoObjectsOverText":
                    layoutValue = SlideLayout.ppLayoutTwoObjectsOverText;
                    break;
                case "ppLayoutFourObjects":
                    layoutValue = SlideLayout.ppLayoutFourObjects;
                    break;
                case "ppLayoutCustom": //future development, unknown layout for now
                default:
                    break;
            }
            return layoutValue;
        }

        private int ParseIndexAttribute(XmlNode slideXmlNode){
            Check.Require(slideXmlNode.Attributes[indexAttr] != null, "index attribute not present");
            return Int32.Parse(slideXmlNode.Attributes[indexAttr].Value);
        }
    }
}